-- PetShopM
-- Created by chendh
-- 佣兵营地模块

module("PetShopM", package.seeall);

-- 配置
local petShopConfig = {};
local goldenPotUseBonusConfig = {};
local petList       = {};
local autoRefreshTime;
local maxBonusNum = 0;

-- 碎片兑换信息
local shopInfo = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 转换下pet_shop配置表
    local pet_shop_CSV = get_pet_shop_CSV();
    local golden_CSV = get_golden_pot_use_bonus_CSV();
    for i = 1, #pet_shop_CSV do
        -- 解析出商品信息
        petShopConfig[pet_shop_CSV[i].id] = parseGoods(pet_shop_CSV[i]);
        petList[pet_shop_CSV[i].pet_id] = petShopConfig[pet_shop_CSV[i].id];
    end

    -- 黄金罐奖励配置表
    for i = 1, #golden_CSV do
        goldenPotUseBonusConfig[golden_CSV[i].id] = golden_CSV[i];
        if golden_CSV[i]["count"] > maxBonusNum then
            maxBonusNum = golden_CSV[i]["count"];
        end
    end

    pet_shop_CSV = {};
    golden_CSV = {};
end

-- 初始化
function init()
    loadCsv();

    shopInfo = {};
    autoRefreshTime = nil;
end

-- 解析商品数据
function parseGoods(info)
    -- 价格
    local ret = {}
    local arr = string.explode(string.sub(info.price, 3, -2), ",");
    if string.startWith(info.price, "1(") then
        -- 物品
        ret = { 1, tonumber(arr[1]), tonumber(arr[2]), }
    elseif string.startWith(info.price, "2(") then
        -- 属性
        ret = { 2, arr[1], tonumber(arr[2]), }
    else
        assert(0);
    end

    info.price = ret;

    return info
end

-- 获取商品
function query(goodsId)
    -- 返回商品
    return petShopConfig[goodsId];
end

-- 检索商品价格
function queryPrice(goodsId)
    if petShopConfig[goodsId] then
        return petShopConfig[goodsId].price;
    else
        return nil;
    end
end

-- 获取商店信息(根据冈布奥阵营)
function getGoodsByCamp(campId)
    local ret = {};
    if petShopConfig == nil then
        return ret;
    end

    for _, info in pairs(petShopConfig) do
        local petId = info.pet_id;
        if CampM.getPetCamp(petId) == campId then
            -- 只获取指定阵营的
            table.insert(ret, info);
        end
    end
    return ret;
end

-- 获取当前阵营可以兑换的冈布奥ID
function getGoodsNumByCamp(campId)
    local ret = {};
    local infos = getGoodsByCamp(campId);
    for _, info in pairs(infos) do
        if not PetM.getMyPet(info.pet_id) then
            table.insert(ret, info.pet_id);
        end
    end
    return ret;
end

-- 获取当前可以被招募的冈布奥
function getCanHireSlimeByCamp(campId)
    local infos = getGoodsByCamp(campId);
    local ret = 0;
    for _, info in pairs(infos) do
        if ItemM.getAmount(ME.user, info.price[2]) >= info.price[3] and
            not PetM.getMyPet(info.pet_id) then
            -- 碎片足够/尚未获得
            if info.activity ~= 1 then
                -- 不是活动的
                ret = info.pet_id;
                break;
            elseif canActivityPetHire(info.pet_id) then
                -- 是活动的，判断可以召唤
                ret = info.pet_id;
                break;
            end
        end
    end
    return ret;
end

-- 活动冈布奥是否可以被召唤
function canActivityPetHire(petId)
    if PetM.query(petId, "get_type") ~= ACTIVITY then
        -- 不是活动类型的
        return false;
    end

    -- 判断是否曾经开过活动
    local dbase = PetM.query(petId, "dbase") or {};
    local activityId = dbase["activity_id"] or 0;
    return ActivityM.hasActivityOpenOnce(activityId);
end

-- 获取当前可以被招募的冈布奥
function getCanHireSlime()
    local campIds = {2, 1, 3, 4};
    local ret = 0;
    for _, campId in pairs(campIds) do
        local classId = getCanHireSlimeByCamp(campId);
        if classId > 0 then
            ret = classId;
            break;
        end
    end
    return ret;
end

-- 获取所有商品
function getAllGoods()
    if petShopConfig == nil then
        return {};
    end

    return petShopConfig;
end

--------------------------------
-- 判断能否购买
-- @param goodsId    商品id
-- @return 如果可以购买，返回true，否则返回错误码
function canBuyGoods(goodsId)
    local priceInfo = queryPrice(goodsId);

    if ItemM.getAmount(ME.user, priceInfo[2]) < priceInfo[3] then
        -- 用于兑换的荣誉碎片不足
        return nil;
    end

    if ME.user.pets[query(goodsId).pet_id] then
        -- 宠物已激活
        return nil;
    end

    return true;
end

-- 当前是否有可以兑换的宠物
function havePetToExchange()
    for id, info in ipairs(petShopConfig) do
        if canBuyGoods(id) then
            if info.activity ~= 1 then
                -- 检查提示，不是活动副本的
                return id;
            elseif canActivityPetHire(info.pet_id) then
                -- 是活动的，并且可以召唤
                return id;
            end
        end
    end

    return nil;
end

-- 获取荣誉碎片的图片
function getHonorScrapIcon(petId, itemId)
    local honorScrapPath = "images/ui/attrib/";

    local fullName = honorScrapPath .. "honor_scrap" .. petId .. ".png";
    if cc.FileUtils:getInstance():isFileExist(fullName) then
        return fullName;
    else
        return getItemIconPath(itemId);
    end
end

-- 获取兑换冈布奥所需的荣誉碎片数量
function getExchangeScrapCost(petId)
    local costInfo = petList[petId];

    if costInfo == nil then
        return -1;
    else
        return costInfo.price[3];
    end
end

-- 更新兑换信息
function updateInfo(info)
    shopInfo = info;

    if not autoRefreshTime then
        autoRefreshTime = shopInfo["auto_refresh_time"];
    elseif autoRefreshTime ~= shopInfo["auto_refresh_time"] then
        -- 自动更新了，需要重绘界面，抛出事件
        EventMgr.fire(event.PET_SHOP_EXCHANGE, { ["goodsId"] = nil, ["result"] = nil });
        autoRefreshTime = shopInfo["auto_refresh_time"];
    end
end

-- 获取商店信息
function getShopInfo()
    return shopInfo;
end

-- 获取商店自动刷新时间
function getShopAutoRefreshTime()
    if shopInfo ~= nil and shopInfo.auto_refresh_time ~= nil then
        return shopInfo.auto_refresh_time;
    end

    return 0;
end

-- 商店刷新剩余时间
function getShopAutoRefreshLeftTime()
    local serverTime = TimeM.getServerTime();
    if shopInfo ~= nil and shopInfo.auto_refresh_time ~= nil then
        return shopInfo.auto_refresh_time - serverTime;
    end

    return 0;
end

-- 获取商店商品
function getAllScrapGoods()
    local list = {};
    if shopInfo == nil or shopInfo.goods == nil then
        return {};
    end

    -- 按照位置升序
    local indexList = table.keys(shopInfo.goods);
    table.sort(indexList);

    for _, index in pairs(indexList) do
        local info = shopInfo.goods[index];
        table.insert(list, info);
    end

    return list;
end

-- 获取当前可以被兑换的碎片ID
function getCanChangeScarp()
    local infos = getAllScrapGoods();
    local ret = 0;
    for _, info in pairs(infos) do
        if ItemM.getAmount(ME.user, info.dungeon_pet_chips) >= info.dungeon_chips_cost
           and info.sold_out ~= 1 then
            ret = info.rare_pet_chips;
            break;
        end
    end
    return ret;
end

-- 根据索引获得商店出售物品信息
function getGoodInfoInShop(goodsIndex)
    if shopInfo == nil then
        return nil;
    end

    return shopInfo.goods[goodsIndex];
end

-- 判断能否购买物品，只判断价格
function canChangeScraps(goodsIndex)
    local info = shopInfo;

    -- 没有该商店或者商品信息
    if not info or not info.goods[goodsIndex] then
        return false
    end

    -- 如果已经买过了
    if info.goods[goodsIndex].sold_out == 1 then
        return "sold_out"   -- 商品已售完
    end

    local priceIndex = info.goods[goodsIndex].price;
    local goodsId = info.goods[goodsIndex].goods_id;
    local arr = queryPrice(goodsId, priceIndex);
    local ok = true;

    local costItemId = info.goods[goodsIndex].dungeon_pet_chips;
    local costNum = info.goods[goodsIndex].dungeon_chips_cost;

    -- 判断物品是否足够
    ok = (ItemM.getAmount(ME.user, costItemId) >= costNum);
    if not ok then
        return "item_lack"   -- 物品数量不足
    end

    return ok;
end

-- 是否能够购买罐子
function canBuyPuzzleBox(puzzleType, num)
    local limitCount = ServerStatusM.query("golden_pot_buy_limit") or 0;
    limitCount = FormulaM.invoke("CALC_GOLDEN_POT_BUY_LIMIT", limitCount);
    if limitCount > 0 then
        -- 服务器限制了购买次数
        local dailyOperationLimit = ME.user.dbase:query("daily_operation_limit", {});
        local operationCount = dailyOperationLimit["operation_count"] or {};
        local buyNum;
        if puzzleType == "gem" then
            buyNum = operationCount["golden_pot_buy"] or 0
        else
            buyNum = operationCount["normal_pot_buy"] or 0
        end

        if buyNum + num > limitCount then
            -- 超过了
            return false;
        end
    end

    local cost = FormulaM.invoke("CALC_PUZZLE_BOX_COST", puzzleType);
    if cost[1] == 1 then
        return ItemM.getAmount(ME.user, cost[2]) >= cost[3] * num;
    elseif cost[1] == 2 then
        return ME.user.dbase:query(cost[2], 0) >= cost[3] * num;
    end
end

-- 购买罐子
function buyPuzzleBox(puzzleType, num)
    -- 能否购买
    if not canBuyPuzzleBox(puzzleType, num) then
        return false;
    end

    local cost = FormulaM.invoke("CALC_PUZZLE_BOX_COST", puzzleType);
    if cost[1] == 1 then
        if not ItemM.costAmount(ME.user, cost[2], cost[3] * num) then
            return false;
        end
    elseif cost[1] == 2 then
        if not ME.user:costAttrib(cost[2], cost[3] * num) then
            return false;
        end
    end

    local classId = FormulaM.invoke("CALC_PUZZLE_BOX_COST_CLASS_ID", puzzleType);

    -- 奖励
    BonusM.doBonus({1, classId, num}, "buy_puzzle_box");

    -- 服务器限制了购买次数，需要限制购买次数
    local limitCount = ServerStatusM.query("golden_pot_buy_limit") or 0;
    limitCount = FormulaM.invoke("CALC_GOLDEN_POT_BUY_LIMIT", limitCount);
    if limitCount > 0 then
        -- 服务器限制了购买次数
        local dailyOperationLimit = ME.user.dbase:query("daily_operation_limit", {});
        local operationCount = dailyOperationLimit["operation_count"] or {};

        if puzzleType == "gem" then
            operationCount["golden_pot_buy"] = tonumber(operationCount["golden_pot_buy"]) + num;
        else
            operationCount["normal_pot_buy"] = tonumber(operationCount["normal_pot_buy"]) + num;
        end

        dailyOperationLimit["operation_count"] = operationCount;

        ME.user.dbase:set("daily_operation_limit", dailyOperationLimit);
    end

    -- 抛出事件
    EventMgr.fire(event.BUY_PUZZLE_BOX, { ["puzzleType"] = puzzleType, ["amount"] = num });

    if puzzleType == "gem" then
        local add_score = FormulaM.invoke("CALC_BLACK_MARKET_ADD_SCORE", "gem", cost[3] * num);
        local score = ME.user.dbase:query("gold_tank_score") or 0;
        ME.user.dbase:set("gold_tank_score", score + add_score);

        -- 尝试奖励
        goldTankScoreBonus(score);
    else
        -- 购买普通罐
        -- 获取一个随机数
        local seed = RandomFactoryM.myRandom(ME.user);
        local seed2 = RandomFactoryM.myRandom(ME.user);
        local ret = FormulaM.invoke("CALC_NORMAL_TANK_BONUS", cost[3] * num, seed);

        if ret then
            if seed2 % 4 < 1 then
                -- 触发黄金罐奖励
                SlimeEventM.triggerEvent(202);
            else
                -- 触发普通罐奖励
                SlimeEventM.triggerEvent(203);
            end
        end
    end

    return true;
end

-- 佣兵首领黄金罐积分奖励
function goldTankScoreBonus(oriScore)
    if not PetM.getMyPet(79) then
        SlimeEventM.triggerEvent(200, { ["ori_score"] = oriScore});
    else
        SlimeEventM.triggerEvent(201, { ["ori_score"] = oriScore});
    end
end

-- 判断玩家能否领取
function canTakePotUseBonus(campId)
    local record = table.deepcopy(ME.user.dbase:query("golden_pot_use_record", {}));
    local campRecord = record[campId] or {};
    -- 获得使用数量和当前领取进度
    local useNum = campRecord.use_num or 0;
    local progress = campRecord.progress or 0;
    local nextPorgerss = progress + 1 + campId * 100;

    local bonusInfo = goldenPotUseBonusConfig[nextPorgerss];
    if not bonusInfo or useNum < bonusInfo["count"] then
        -- 没有达到获奖数量
        return false;
    end
    return true;
end

-- 获取当前阵营可以领取的
function takePotUseBonusNum(campId)
    local count = 0;
    for id, info in pairs(goldenPotUseBonusConfig) do
        if info.camp_id == campId then
            if not isTakeGoldenPotUseBonus(id)
                and canTakePotUseBonusById(id) then
                count = count + 1;
            end
        end
    end
    return count;
end

-- 查询奖励
function queryGoldenPotBonus(id)
    if not id then
        return goldenPotUseBonusConfig;
    end
    return table.deepcopy(goldenPotUseBonusConfig[id]);
end

-- 最多可以领取奖励的数量
function getMaxBonusNum()
    return maxBonusNum;
end

-- 判断玩家能否领取某个ID 奖励
function canTakePotUseBonusById(id)
    local campId = math.floor(id / 100);
    local record = table.deepcopy(ME.user.dbase:query("golden_pot_use_record", {}));
    local campRecord = record[campId] or {};
    -- 获得使用数量
    local useNum = campRecord.use_num or 0;
    local bonusInfo = goldenPotUseBonusConfig[id];
    if useNum < bonusInfo["count"] then
        -- 没有达到获奖数量
        return false;
    end
    return true;
end

-- 是否已经领取了
function isTakeGoldenPotUseBonus(id)
    local record = table.deepcopy(ME.user.dbase:query("golden_pot_use_record", {}));
    local campId = math.floor(id / 100);
    local campRecord = record[campId] or {};
    -- 获得当前领取进度
    local progress = campRecord.progress or 0;
    local progressId = campId * 100 + progress;
    if id > progressId then
        -- 还没领取
        return false;
    end
    return true;
end

-- 玩家请求领取奖励
function takeGoldenPotUseBonus(campId)
    local record = table.deepcopy(ME.user.dbase:query("golden_pot_use_record", {}));
    local campRecord = record[campId] or {};
    -- 获得使用数量和当前领取进度
    local useNum = campRecord.use_num or 0;
    local progress = campRecord.progress or 0;
    local nextPorgerss = progress + 1 + campId * 100;

    local bonusInfo = goldenPotUseBonusConfig[nextPorgerss];

    if not bonusInfo or useNum < bonusInfo["count"] then
        -- 没有达到获奖数量
        return false;
    end

    local bonus = bonusInfo["bonus"];
    -- 直接奖励
    BonusM.doBonus(bonus, "golden_pot_ex_bonus");

    -- 更新进度
    campRecord["progress"] = progress + 1;
    record[campId] = campRecord;

    ME.user.dbase:set("golden_pot_use_record", record);

    -- 弹出获奖界面
    EventMgr.fire(event.TAKE_GOLDEN_POT_BONUS, {["bonus"] = bonus});

    return true;
end

-- 使用罐子
----///// 这个函数废弃了
function usePuzzleBox(puzzleType, num, campId)
    if true then
        return;
    end

    -- 需要检查当前是否有可抽取的
    if puzzleType == "gem" then
        local gemArr = {};
        -- 可抽取的碎片
        local commonTypes = FormulaM.invoke("CALC_POT_PET_RANGE");
        local i;
        for i = 1, #commonTypes do
            gemArr = table.append(gemArr, PetM.getFetchSlimeList(campId, commonTypes[i], true));
        end

        if #gemArr <= 0 then
            return false;
        end
    end

    -- 先删除触发标记
    ME.user.dbase:deleteTemp("use_pot_trigger");

    -- 罐子的classId
    local classId = FormulaM.invoke("CALC_PUZZLE_BOX_COST_CLASS_ID", puzzleType);

    -- 扣除
    if not ItemM.costAmount(ME.user, classId, num) then
        return false;
    end

    local bonusList = {};
    for i = 1, num do
        -- 获取一个随机数
        local seed = RandomFactoryM.myRandom(ME.user);
        -- 根据类型计算奖励
        bonus = FormulaM.invoke("CALC_PUZZLE_BOX_BONUS", puzzleType, seed, campId);
        -- 直接奖励
        BonusM.doBonus(bonus, "use_puzzle_box");
        -- 收集奖励信息
        table.insert(bonusList, bonus);
    end

    if puzzleType == "gem" then
        -- 黄金罐使用记录
        local record = ME.user.dbase:query("golden_pot_use_record", {});
        local campRecord = record[campId] or {};
        campRecord["use_num"] = (campRecord["use_num"] or 0) + num;
        record[campId] = campRecord;
        ME.user.dbase:set("golden_pot_use_record", record);
    end

    -- 抛出事件
    EventMgr.fire(event.USE_PUZZLE_BOX, { ["bonusList"] = bonusList, ["puzzleType"] = puzzleType});
    return true;
end

-- 是否有未使用的冈布奥的罐
function havePuzzleBox()
    local gemBoxClassId = FormulaM.invoke("CALC_PUZZLE_BOX_COST_CLASS_ID", "gem");
    local moneyBoxClassId = FormulaM.invoke("CALC_PUZZLE_BOX_COST_CLASS_ID", "money");
    if ItemM.getAmount(ME.user, gemBoxClassId) > 0 or ItemM.getAmount(ME.user, moneyBoxClassId) > 0 then
        return true;
    end
    return false;
end

-- 是否是佣兵营地的冈布奥
function isInPetShop(petId)
    for _, info in pairs (petShopConfig) do
        if info["pet_id"] == petId then
            return true;
        end
    end
    return false;
end

-- 获取某冈布奥是否可以被招募
function canHirePet(classId)
    local campId = CampM.getPetCamp(classId);
    local infos = getGoodsByCamp(campId);

    for _, info in pairs(infos) do
        if info.pet_id == classId
            and ItemM.getAmount(ME.user, info.price[2]) >= info.price[3]
            and not PetM.getMyPet(info.pet_id) then
                return true;
        end
    end

    return false;
end